import pandas as pd
from copy import deepcopy

class wavelet_llt:
    def __init__(self,period=30):
        self.a=2/(period+1)
        self.data=0
        self.predata=[]
        self.pret=[]
    def ondata(self,t):
        if len(self.predata)<2:
            self.data=t
            self.predata.append(self.data)
            self.pret.append(t)
        else:
            self.data=(self.a-self.a**2/4)*t+self.a**2/2*self.pret[1]-(self.a-3*self.a**2/4)*self.pret[0]+2*(1-self.a)*self.predata[1]-(1-self.a)**2*self.predata[0]
            self.predata.pop(0)
            self.pret.pop(0)
            self.predata.append(self.data)
            self.pret.append(t)
        return self.data

class base:
    def __init__(self,period=30):
        self.a=2/(period+1)
        self.data=0
        self.predata=[]
        self.pret=[]
    def ondata(self,t):
        if len(self.predata)<2:
            self.data=t
            self.predata.append(self.data)
            self.pret.append(t)
        else:
            self.data=(self.a-self.a**2/4)*t+self.a**2/2*self.pret[1]-(self.a-3*self.a**2/4)*self.pret[0]+2*(1-self.a)*self.predata[1]-(1-self.a)**2*self.predata[0]
            self.predata.pop(0)
            self.pret.pop(0)
            self.predata.append(self.data)
            self.pret.append(t)
        return self.data
class calcor_base:
    def __init__(self,timeperiod=2,inputs=1,mintimeperiod=None,datatype="bar",nadata_deal="fillpre"):
        """"
        Args:
            timeperiod: 时间序列
            inputs: 入参个数
            mintimeperiod: 最小运行数量
            datatype: bar,dim1,dimn,selfdata
            nadata_deal:na值的处理方式:drop,初始drop,后续使用前值填充;不处理 初始是否处理,后续怎么处理 fillpre None,drop
        """
        self.hisdata=[]
        self.lasttimekey = None
        self.set_args(timeperiod,inputs,mintimeperiod,datatype,nadata_deal)
    def set_args(self,timeperiod=2,inputs=1,mintimeperiod=None,datatype="bar",nadata_deal="fillpre"):
        self.inputs=inputs
        self.nadata_deal = nadata_deal
        self.datatype=datatype
        if isinstance(inputs,int):
            self.ishisdict=False
            if inputs>1 and datatype!="bar":
                for i in range(inputs):
                    self.hisdata.append([])
        else:
            if datatype=="bar":
                self.ishisdict = True
                self.hisdata={}
                for k in inputs:
                    self.hisdata[k]=[]
            else:
                self.ishisdict = False
                if inputs > 1:
                    for i in range(inputs):
                        self.hisdata.append([])
        self.timeperiod=timeperiod
        if mintimeperiod:
            self.mintimeperiod=mintimeperiod
        else:
            self.mintimeperiod=timeperiod
        if datatype =="dim1":
            self.oncalc=self.ondata_dim1
        elif datatype=="dimn":
            self.oncalc=self.ondata_dimn
        elif datatype=="dimn1":
            self.oncalc=self.ondata_dimn1
        elif datatype == "bar":
            self.oncalc = self.ondata_bar
        else:
            self.calc=self.calc_None
    def calc_None(self):
        return None
    def ondata_dimn(self,*bb,timekey=None):
        b=[]
        n=0
        n0 =len(bb)
        n1=len(self.hisdata)
        if n0!=n1:
            n2=n0-n1
            for i in range(n2):
                self.hisdata.append([])
        for i in bb:
            if pd.isna(i):
                if self.nadata_deal=="fillpre":
                    if not self.hisdata[n]:
                        return None
                    else:
                        i=self.hisdata[n][-1]
                        b.append(i)
                elif self.nadata_deal=="drop":
                    if not self.hisdata[n]:
                        return None
            else:
                b.append(i)
            n=n+1
        ss=[]
        if timekey   is not None:
            if self.lasttimekey == timekey:
                n=0
                for i in b:
                    if self.hisdata[n]:
                        self.hisdata[n][-1] = i
                    else:
                        self.hisdata[n].append(i)
                    n=n+1
                    ss.append(len(self.hisdata[n]))
            else:
                n = 0
                for i in b:
                    self.hisdata[n].append(i)
                    if len(self.hisdata[n]) > self.timeperiod:
                        self.hisdata[n].pop(0)
                    ss.append(len(self.hisdata[n]))
                    n = n + 1
            self.lasttimekey = timekey
        else:
            n=0
            for i in b:
                self.hisdata[n].append(i)
                if len(self.hisdata[n]) > self.timeperiod:
                    self.hisdata[n].pop(0)
                ss.append(len(self.hisdata[n]))
                n = n + 1
        min0=min(ss)
        if min0>=self.mintimeperiod:
            r = self.calc()
            return r
    def ondata_dimn1(self,*b,timekey=None):
        if pd.isna(b):
            if self.nadata_deal=="fillpre":
                if not self.hisdata:
                    return None
                else:
                    b=self.hisdata[-1]
            elif self.nadata_deal=="drop":
                if not self.hisdata:
                    return None
        if timekey   is not None:
            if self.lasttimekey == timekey:
                if self.hisdata:
                    self.hisdata[-1] = b
                else:
                    self.hisdata.append(b)
            else:
                self.hisdata.append(b)
                if len(self.hisdata) > self.timeperiod:
                    self.hisdata.pop(0)
            self.lasttimekey = timekey
        else:
            self.hisdata.append(b)
            if len(self.hisdata) > self.timeperiod:
                self.hisdata.pop(0)
        if len(self.hisdata)>=self.mintimeperiod:
            r = self.calc()
            return r
    def ondata_dim1(self,b,timekey=None):
        if pd.isna(b):
            if self.nadata_deal=="fillpre":
                if not self.hisdata:
                    return None
                else:
                    b=self.hisdata[-1]
            elif self.nadata_deal=="drop":
                if not self.hisdata:
                    return None
        if timekey   is not None:
            if self.lasttimekey == timekey:
                if self.hisdata:
                    self.hisdata[-1] = b
                else:
                    self.hisdata.append(b)
            else:
                self.hisdata.append(b)
                if len(self.hisdata) > self.timeperiod:
                    self.hisdata.pop(0)
            self.lasttimekey = timekey
        else:
            self.hisdata.append(b)
            if len(self.hisdata) > self.timeperiod:
                self.hisdata.pop(0)
        if len(self.hisdata)>=self.mintimeperiod:
            r = self.calc()
            return r
    def ondata_bar(self,bar,timekey=None):
        if self.ishisdict:
            bb={}
            if pd.isna(bar):
                if self.nadata_deal=="fillpre":
                    for k in self.inputs:
                        if not self.hisdata[k]:
                            return None
                        else:
                            b0=self.hisdata[k][-1]
                            bb[k]=b0
                elif self.nadata_deal=="drop":
                    for k in self.inputs:
                        if not self.hisdata[k]:
                            return None
            else:
                for k in self.inputs:
                    v=bar[k]
                    if pd.isna(v):
                        if self.nadata_deal == "fillpre":
                            if not self.hisdata[k]:
                                return None
                            else:
                                b0 = self.hisdata[k][-1]
                                bb[k] = b0
                        elif self.nadata_deal == "drop":
                            if not self.hisdata[k]:
                                return None
                        
            if bb:
                b=deepcopy(bar)
                b.update(bb)
            else:
                b=bar
            ss = []
            if timekey   is not None:
                if self.lasttimekey == timekey:
                    for k in self.inputs:
                        if self.hisdata[k]:
                            self.hisdata[k][-1] = b[k]
                        else:
                            self.hisdata[k].append(b[k])
                        ss.append(len(self.hisdata[k]))
                else:
                    for k in self.inputs:
                        self.hisdata[k].append(b[k])
                        ss.append(len(self.hisdata[k]))
                        if len(self.hisdata[k]) > self.timeperiod:
                            self.hisdata[k].pop(0)
                self.lasttimekey = timekey
            else:
                for k in self.inputs:
                    self.hisdata[k].append(b[k])
                    ss.append(len(self.hisdata[k]))
                    if len(self.hisdata[k]) > self.timeperiod:
                        self.hisdata[k].pop(0)
            min0=min(ss)
            if min0>=self.mintimeperiod:
                r = self.calc()
                return r
        else:
            b=bar
            if pd.isna(b):
                if self.nadata_deal=="fillpre":
                    if not self.hisdata:
                        return None
                    else:
                        b=self.hisdata[-1]
                elif self.nadata_deal=="drop":
                    if not self.hisdata:
                        return None
            if timekey   is not None:
                if self.lasttimekey == timekey:
                    if self.hisdata:
                        self.hisdata[-1] = b
                    else:
                        self.hisdata.append(b)
                else:
                    self.hisdata.append(b)
                    if len(self.hisdata) > self.timeperiod:
                        self.hisdata.pop(0)
                self.lasttimekey = timekey
            else:
                self.hisdata.append(b)
                if len(self.hisdata) > self.timeperiod:
                    self.hisdata.pop(0)
            if len(self.hisdata)>=self.mintimeperiod:
                r=self.calc()
                return r